﻿using GACore;
using GACore.InputArgs;
using System;
using System.Collections.Generic;
using System.Xml.Linq;

namespace PflanzenZAOptimierung
{
	class Program
	{
		static void Main(string[] args)
		{
			try
			{
				if (args == null || args.Length == 0)
				{
					throw new ArgumentException("Es wurde keine Einstellungsdatei übergeben." + Environment.NewLine + "Bitte übergeben Sie den Pfad zur Einstellungsdatei als Parameter in der Kommandozeile.");
				}
				Persistence peristence = new Persistence(args[0]);
				Controller controller = Controller.Instance;
				Persistence.AddIndividualPreferences aip = new Persistence.AddIndividualPreferences(AddStepCountPreference);
				aip += new Persistence.AddIndividualPreferences(AddInitialStepCountPreferences);
				aip += new Persistence.AddIndividualPreferences(AddCellDefinitionsPathPreferences);
				aip += new Persistence.AddIndividualPreferences(AddEnvironmentDefinitionsPathPreferences);
				aip += new Persistence.AddIndividualPreferences(AddRuleDefinitionsPathPreferences);
				controller.Init(peristence.Load(aip), new PlantsCAProblem((int)peristence.IndividualPreferences["StepCount"],
					(int)peristence.IndividualPreferences["InitialStepCount"], (string)peristence.IndividualPreferences["CellDefinitions"],
					(string)peristence.IndividualPreferences["EnvironmentDefinitions"], (string)peristence.IndividualPreferences["RuleDefinitions"]));
				controller.Optimize();
			}
			catch (Exception ex)
			{
				Console.WriteLine("Es ist ein Fehler mit folgender Meldung aufgetreten:" + Environment.NewLine + ex.Message);
			}
		}

		static void AddCellDefinitionsPathPreferences(XElement root, ref Dictionary<string, object> prefs)
		{
			prefs.Add("CellDefinitions", GetElementAsString(root, "CellDefinitions"));
		}

		static void AddEnvironmentDefinitionsPathPreferences(XElement root, ref Dictionary<string, object> prefs)
		{
			prefs.Add("EnvironmentDefinitions", GetElementAsString(root, "EnvironmentDefinitions"));
		}

		static void AddRuleDefinitionsPathPreferences(XElement root, ref Dictionary<string, object> prefs)
		{
			prefs.Add("RuleDefinitions", GetElementAsString(root, "RuleDefinitions"));
		}

		static void AddStepCountPreference(XElement root, ref Dictionary<string, object> prefs)
		{
			prefs.Add("StepCount", GetElementAsInt(root, "StepCount"));
		}

		static void AddInitialStepCountPreferences(XElement root, ref Dictionary<string, object> prefs)
		{
			prefs.Add("InitialStepCount", GetElementAsInt(root, "InitialStepCount"));
		}

		private static int GetElementAsInt(XElement root, string elementName)
		{
			try
			{
				return (int)GetElementFromRoot(root, elementName);
			}
			catch
			{
				throw new ArgumentException("Das Element " + root.Name + " ist kein Integer.");
			}
		}

		private static string GetElementAsString(XElement root, string elementName)
		{
			try
			{
				return (string)GetElementFromRoot(root, elementName);
			}
			catch
			{
				throw new ArgumentException("Das Element " + root.Name + " ist kein String.");
			}
		}

		private static XElement GetElementFromRoot(XElement root, string elementName)
		{
			XElement current = root.Element(elementName);
			if (current == null)
			{
				throw new ArgumentException("Das Element mit dem Namen " + elementName + " ist nicht vorhanden.");
			}
			return current;
		}

	}
}
